package com.supplychainapi.filter;

import com.alibaba.fastjson.JSON;
import com.supplychainapi.common.RestResponse;
import com.supplychainapi.utils.MD5Utils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 手机端签名验证
 *
 * @author xiezhiwei
 */
@Component
public class PhoneSignIntercepter implements HandlerInterceptor {

    private Logger logger = LoggerFactory.getLogger(PhoneSignIntercepter.class);

    @Value("${posKey}")
    private String posKey;

    // 环境 dev=开发  test=测试  prod=生产
    @Value("${spring.profiles.active}")
    private String active;

    // 当前生成的sign
    private String tSign = "";

    // 公共参数
    private Map<String, String> commonParameters = new HashMap<String, String>();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }

        logger.info("签名验证");

        // 针对所有的请求写日志
        loggerInfo(request);

        if (!getCommonParameters(request, response)) {
            return false;
        }

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        logger.info("-----postHandle-----");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        logger.info("-----afterCompletion-----");
    }

    /**
     * 验证和获取手机端公共参数
     *
     * @param request
     * @param response
     */
    private Boolean getCommonParameters(HttpServletRequest request, HttpServletResponse response) {
        // 登录Token
        String Token = request.getHeader("Token");
        // 返回消息的格式化方式；取值：JSON；默认值：JSON
        String Format = request.getHeader("Format");
        // 签名算法版本，目前版本是1.0，取值：1.0
        String SignatureVersion = request.getHeader("SignatureVersion");
        // 来源;Android;IOS
        String Source = request.getHeader("Source");
        // 签名结果串，关于签名的计算方法
        String Signature = request.getHeader("Signature");
        // 唯一随机数，用于防止网络重放攻击。用户在不同请求间要使用不同的随机数值
        String SignatureNonce = request.getHeader("SignatureNonce");
        // 请求的时间戳。日期格式按照ISO8601标准表示，并需要使用UTC时间。格式为： YYYY-MM-DDThh:mm:ssZ 例如，2013-01-10T12:00:00Z（为北京时间2013年1月10日20点0分0秒）
        String Timestamp = request.getHeader("Timestamp");

        if (StringUtils.isBlank(Token)) {
            Token = "";
        }

        if (!(StringUtils.isNotBlank(Format) && "JSON".equals(Format))) {
            responseResult(response, RestResponse.fail(400, 400002, "参数错误"));
            return false;
        }

        if (StringUtils.isBlank(SignatureVersion)) {
            responseResult(response, RestResponse.fail(400, 400003, "参数错误"));
            return false;
        }

        if (!(StringUtils.isNotBlank(SignatureVersion) && "1.0".equals(SignatureVersion))) {
            responseResult(response, RestResponse.fail(400, 400004, "参数错误"));
            return false;
        }

        if (StringUtils.isBlank(Signature)) {
            responseResult(response, RestResponse.fail(400, 400005, "参数错误"));
            return false;
        }

        if (StringUtils.isBlank(SignatureNonce)) {
            responseResult(response, RestResponse.fail(400, 400006, "参数错误"));
            return false;
        }

        if (StringUtils.isBlank(Timestamp)) {
            responseResult(response, RestResponse.fail(400, 400007, "参数错误"));
            return false;
        }

        commonParameters.put("Token", Token);
        commonParameters.put("Format", Format);
        commonParameters.put("Signature", Signature);
        commonParameters.put("SignatureVersion", SignatureVersion);
        commonParameters.put("Source", Source);
        commonParameters.put("SignatureNonce", SignatureNonce);
        commonParameters.put("Timestamp", Timestamp);

        if (!checkSign(request)) {
            // 开发和测试环境返回签名
            if (active.equals("dev") || active.equals("test")) {
                responseResult(response, RestResponse.fail(400, 400008, "签名验证错误,当前可用sign，用在测试环境：" + tSign));
            } else {
                responseResult(response, RestResponse.fail(400, 400008, "参数错误"));
            }
            return false;
        }
        return true;
    }


    /**
     * 验证手机端请求签名是否正确
     *
     * @param request
     * @return
     */
    private Boolean checkSign(HttpServletRequest request) {

//        String method = request.getMethod();
        String Signature = commonParameters.get("Signature");
        Map<String, String> map = new HashMap<String, String>();
        commonParameters.forEach((String key, String value) -> {
            if (!"Signature".equals(key)) {
                map.put(key, value);
            }
        });
        // GET 中参数提取
        Map<String, String[]> param_maps = request.getParameterMap();
        for (Map.Entry<String, String[]> entry : param_maps.entrySet()) {
            if (entry.getValue() != null && entry.getValue().length > 0) {
                map.put(entry.getKey(), entry.getValue()[0]);
            } else {
                map.put(entry.getKey(), "");
            }
        }
        // POST json字符串提取
        try {
            String body = IOUtils.toString(request.getInputStream(), "utf-8");
            String upload=request.getHeader("Content-Type");
            if(null!=upload && !upload.contains("multipart/form-data")){//文件上传不参与验签
                map.put("body", body);
                logger.info("文件上传body不参与验签");
            }else{
                String url = request.getRequestURI().substring(request.getContextPath().length());
                if(!url.contains("uploadImage")){
                    logger.info("文件上传body不参与验签");
                    map.put("body", body);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        tSign = MD5Utils.getSign(map, posKey);
        return tSign.equals(Signature);
    }

    /**
     * 后台的请求进行统一日志处理
     *
     * @param request
     */
    private void loggerInfo(HttpServletRequest request) {
        String url = request.getRequestURL().toString();
        String method = request.getMethod();
        String uri = request.getRequestURI();
        String queryString = request.getQueryString();
//		System.out.println(request.getParameterMap());
        logger.info(String.format("请求参数, url: %s, method: %s, uri: %s, params: %s", url, method, uri, queryString));
    }


    /**
     * 回写json数据
     *
     * @param response
     * @param result
     */
    private void responseResult(HttpServletResponse response, RestResponse result) {
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-type", "application/json;charset=UTF-8");
        response.setStatus(200);
        try {
            response.getWriter().write(JSON.toJSONString(result));
        } catch (IOException ex) {
            logger.error(ex.getMessage());
        }
    }
}
